#include <queue>
#include <mutex>
#include <condition_variable>

template <typename T>
class ThreadSafeQueue {
public:
    // 入队操作
    // 获取锁后添加元素，并通知一个等待线程
    void push(T value) {
        std::lock_guard<std::mutex> lock(_mtx);
        if(_finish)  
            return ;

        _data_queue.push(value);
        _cv.notify_one();
    };

    // 非阻塞出队
    // 立即尝试获取元素，若队列为空则返回失败
    bool tryPop(T& value) {
        std::lock_guard<std::mutex> lock(_mtx);
        if(_data_queue.empty() || _finish)
            return false;   // 队列为空 or 终止符为true
    
        value = _data_queue.front();
        _data_queue.pop();
        return true;
    };
    
    // 阻塞出队
    // 等待队列非空后获取元素，处理虚假唤醒
    void waitAndPop(T& value) {
        std::lock_guard<std::mutex> lock(_mtx);
        _cv.wait(lock, [this](){
            return !_data_queue.empty() || _finish;
        });

        if(finish)
            return ;
        value = _data_queue.front();
        _data_queue.pop();
        return ;
    };
        
    // 终止队列
    // 设置终止标志并唤醒所有线程
    void finish() {
        std::lock_guard<std::mutex> lock(_mtx);
        _finish = true;
        _cv.notify_all();
    };

    // 判断队列是否为空
    bool empty() const {
        std::lock_guard<std::mutex> lock(_mtx);
        return _data_queue.empty();
    };

    // 获取队列元素个数
    int size() {
        std::lock_guard<std::mutex> lock(_mtx);
        return _data_queue.size();
    }
private:
    std::queue<T> _data_queue;       // 底层容器就是queue
    std::mutex _mtx;                 // 互斥锁
    std::condition_variable _cv;     // 信号量 
    bool _finish = false;            // 终止标志
};